require 的使用场景
加载模块类型
- 加载内置模块:
require('cluster') - 加载 node_modules 模块:
require('ejs') - 加载本地模块:
require('./ejs')
支持的文件类型
- 加载
.js文件 - 加载
.json文件fs.readFileSync(filename, 'utf8')拿到文件内容,字符串JSON.parse(stripBOM(content))去掉BOM头后解析
- 加载
.node文件return process.dlopen(module, path.toNamespacedPath(filename))
- 加载
.mjs文件 - 加载其类型的文件
- 当
.js文件处理
- 当
require 源码阅读中的一些思考
CommonJS加载主模块的流程- 执行
internal/mian/run_main_modules.js Module._load(process.argv[1], null, true)
- 执行
require为何非将js/json/node文件视为js文件加载?require连续加载同一个模块时,是如何进行缓存的?- 两个缓存
- 父
module的path+\x00文件名对应的绝对路径+文件名.后缀 - 绝对路径+文件名.后缀,对应的
Module对象
- 父
- 两个缓存
主模块特点
process.mainModule = module;require.main = process.mainModule = modulerequire.main === module可以判断模块是主模块
isMain = trueparent为nullprocess.mainModule在node v14.0.0之后弃用
require 执行流程


Module 对象
id: 源码文件路径,如:/User/jolly/Desktop/imooc/ejs-test/ejs.js。根Moduleid为 '.'path: 源码文件所在的文件夹,通过path.dirname(id)生成exports: 模块输出的内容,默认为{}parent: 父模块信息filename: 源码文件路径loaded: 是否已经加载完毕children: 子模块对象集合paths: 模块查询范围
require 执行流程总结
relativeResolveCache[relResolveCacheIdentifier]查询缓存路径Module._cache[filename]查询缓存模块Module._resolveFilename查询模块的只是路径loadNativeModule加载内置模块new Module实例化Module对象module.load加载模块findLongestRegisteredExtension获取文件后缀名Module._extensions[extension](this, filename)解析模块并执行模块module._compile编译模块代码compileFunction将模块代码生成可执行函数exports,require,module,filename,dirname生成入参compileWrapper.call执行模块函数return module.exports输出模块返回结果
扩展资料
阮一峰require源码解读:http://www.ruanyifeng.com/blog/2015/05/require.html
UTF8 BOM:https://www.imooc.com/article/26166
- Shebang:https://blog.csdn.net/u012294618/article/details/78427864
知识点
- path.dirname(filename) 获取文件路径
- path.basename(filename) 获取文件名(带后缀)
- 每需要一次
requirerequireDepth加一,执行完require进来的模块后,requireDepth减一 Module._resolveFilename()调用Module._findPath()之后,在返回的文件名不存在,没有模块,报错Module._nodeModulePaths(path.dirname(filename))产生的node_modules数组,最终保存在了Module对象上- internal/modules/cjs/loader.js findLongestRegisteredExtension(filename) 获取 扩展名,默认返回 js
path.sep 路径分隔符 Mac: '/' window: '\'
'#!' 名字是 shebang
加载内置模块和其他模块的
compileFunction方法来源模块是不一样的